package com.hmkj.core.service.risk.impl;

import com.alibaba.fastjson.JSON;
import com.hmkj.common.baseMapper.GenericMapper;
import com.hmkj.common.baseMapper.GenericPo;
import com.hmkj.core.constant.CacheID;
import com.hmkj.core.constant.RiskNID;
import com.hmkj.core.exception.BussinessException;
import com.hmkj.core.mapper.operate.AgentConfigMapper;
import com.hmkj.core.mapper.risk.RiskParamMapper;
import com.hmkj.core.model.quote.RealTimeData;
import com.hmkj.core.po.commo.Commo;
import com.hmkj.core.po.operate.AgentConfig;
import com.hmkj.core.po.risk.RiskParam;
import com.hmkj.core.service.cache.RedisService;
import com.hmkj.core.service.risk.RiskParamService;
import com.xiaoleilu.hutool.date.DateUtil;
import com.xiaoleilu.hutool.date.Week;
import com.xiaoleilu.hutool.util.StrUtil;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 风控参数表业务相关Service接口实现<br>
 *
 * @author eproo
 * @ClassName: RiskParamServiceImpl
 * @date 2017-11-09 02:38:44
 */
@Service
@Scope("prototype")
@Transactional(rollbackFor = Exception.class)
public class RiskParamServiceImpl implements RiskParamService {

    @Resource
    private RiskParamMapper riskParamMapper;
    @Resource
    private RedisService redisService;
    @Resource
    private AgentConfigMapper agentConfigMapper;

    @Override
    public GenericMapper<RiskParam, Integer> _getMapper() {
        return riskParamMapper;
    }


    @Override
    public void updateRisk(Commo commo, RiskParam risk, Integer type, String value) {
        // 更新数据库
        riskParamMapper.updateByIdAndVersionSelective(new RiskParam(t -> {
            t.setId(risk.getId());
            if (type == 1) {
                t.setValue(value);
            } else {
                t.setDescript(value);
            }
            t.setVersion(risk.getVersion());
        }));

        // 更新缓存
        redisService.put(CacheID.RISK_PREFIX + risk.getNid() + ":" + commo.getId(), value);

    }


    @Override
    public <T> T getParamValue(String nid, Integer commoId, Class<T> clazz) {
        String value = redisService.get(CacheID.RISK_PREFIX + nid + ":" + commoId);
        if (StrUtil.isBlank(value)) {
            RiskParam param = riskParamMapper.selectOne(new RiskParam(t -> {
                t.setCommoId(commoId);
                t.setNid(nid);
            }));
            if (param == null) {
                return null;
            }
            return JSON.parseObject(param.getValue(), clazz);
        }
        if (clazz == String.class) return (T) value;
        return JSON.parseObject(value, clazz);
    }

    @Override
    public String getParamValue(String nid, Integer commoId) {
        return getParamValue(nid, commoId, String.class);
    }

    @Override
    public List<Integer> getParam2IntList(String nid, Integer commoId) {
        String value = redisService.get(CacheID.RISK_PREFIX + nid + ":" + commoId);
        if (StrUtil.isBlank(value)) {
            RiskParam param = riskParamMapper.selectOne(new RiskParam(t -> {
                t.setCommoId(commoId);
                t.setNid(nid);
            }));
            value = param.getValue();
        }

        if (StrUtil.isNotBlank(value)) {
            List<Integer> list = new ArrayList<>();
            String[] args = value.split(",");
            for (String arg : args) {
                list.add(Integer.parseInt(arg));
            }
            return list;
        }
        return null;
    }


    @Override
    public BigDecimal lastPrice(Integer commoId) {
        BigDecimal np = BigDecimal.ZERO;
        RealTimeData realTimeData = redisService.get(CacheID.QUOTE_REAL_PREFIX + commoId, RealTimeData.class);
        if (realTimeData != null) {
            np = realTimeData.getNp();
        }
        return np;
    }

    @Override
    public String getAutoSettleTimeStr(Integer commoId) {
        try {
            SimpleDateFormat f1 = new SimpleDateFormat("yyyy-MM-dd");
            SimpleDateFormat f2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date now = new Date();
            String value = getParamValue(RiskNID.TRADE_TIME, commoId);

            String[] args = value.split(";");
            if (args.length == 1) {
                String[] times = args[0].split(",");
                String settleTimeStr = times[times.length - 1];
                Date settleTime = f2.parse(f1.format(now) + " " + settleTimeStr + ":00");
                if (now.after(settleTime)) {
//                    return "明日 " + settleTimeStr;
                    return settleTimeStr;
                } else {
                    return settleTimeStr;
                }
            } else if (args.length == 2) {
                String[] times1 = args[0].split(",");
                String settleTimeStr1 = times1[times1.length - 1];
                Date settleTime1 = f2.parse(f1.format(now) + " " + settleTimeStr1 + ":00");

                String[] times2 = args[1].split(",");
                String settleTimeStr2 = times2[times2.length - 1];
                Date settleTime2 = f2.parse(f1.format(now) + " " + settleTimeStr2 + ":00");

                if (now.before(settleTime1)) {
                    return settleTimeStr1;
                } else if (now.after(settleTime2)) {
//                    return "明日 " + settleTimeStr2;
                    return settleTimeStr2;
                } else {
                    return settleTimeStr2;
                }
            }
            return "";
        } catch (ParseException e) {
            e.printStackTrace();
            throw new BussinessException("系统繁忙，请稍后再试");
        }
    }

    @Override
    public Date getAutoSettleTime(Integer commoId) {
        try {
            SimpleDateFormat f1 = new SimpleDateFormat("yyyy-MM-dd");
            SimpleDateFormat f2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date now = new Date();
            String value = getParamValue(RiskNID.TRADE_TIME, commoId);

            String[] args = value.split(";");
            if (args.length == 1) {
                String[] times = args[0].split(",");
                String settleTimeStr = times[times.length - 1];
                Date settleTime = f2.parse(f1.format(now) + " " + settleTimeStr + ":00");
                if (now.after(settleTime)) {
                    return DateUtil.offsetDay(settleTime, 1);
                } else {
                    return settleTime;
                }
            } else if (args.length == 2) {
                String[] times1 = args[0].split(",");
                String settleTimeStr1 = times1[times1.length - 1];
                Date settleTime1 = f2.parse(f1.format(now) + " " + settleTimeStr1 + ":00");

                String[] times2 = args[0].split(",");
                String settleTimeStr2 = times2[times2.length - 1];
                Date settleTime2 = f2.parse(f1.format(now) + " " + settleTimeStr2 + ":00");

                if (now.before(settleTime1)) {
                    return settleTime1;
                } else if (now.after(settleTime2)) {
                    return DateUtil.offsetDay(settleTime2, 1);
                } else {
                    return settleTime2;
                }
            }
            return null;
        } catch (ParseException e) {
            e.printStackTrace();
            throw new BussinessException("系统繁忙，请稍后再试");
        }
    }


    @Override
    public boolean isTradeTime(Integer commoId) {
        try {
            SimpleDateFormat f1 = new SimpleDateFormat("yyyyMMddHHmm");
            SimpleDateFormat f2 = new SimpleDateFormat("yyyyMMdd");
            Date now = new Date();

            if (Week.SUNDAY.equals(DateUtil.dayOfWeekEnum(now))) {
                return false;
            }

            List<String[]> periodList = new ArrayList<>();
            String tradeTimeStr = getParamValue(RiskNID.TRADE_TIME, commoId);
            String[] datas = tradeTimeStr.split(";");

            for (int i = 0; i < datas.length; i++) {
                String[] items = datas[i].split("\\|");
                for (int j = 0; j < items.length; j++) {
                    String[] periods = items[j].split(",");
                    periods[1] = periods[1].replace(":", "");
                    periods[0] = periods[0].replace(":", "");
                    periodList.add(periods);
                }
            }

            Date dayStart = f1.parse(f2.format(now) + periodList.get(0)[0]);
            if (now.after(dayStart) && Week.SATURDAY.equals(DateUtil.dayOfWeekEnum(now))){
                return false;
            }

            for (String[] periods : periodList) {
                Date s = f1.parse(f2.format(now) + periods[0]);
                Date e = f1.parse(f2.format(now) + periods[1]);
                if (s.after(e)) {
                    if (now.before(dayStart)){
                        s = DateUtil.offsetDay(s, -1);
                    }else{
                        e = DateUtil.offsetDay(e, 1);
                    }
                }
                if (now.before(e) && now.after(s)) {
                    return true;
                }
            }
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BussinessException("系统繁忙，请稍后再试");
        }
    }


    @Override
    public boolean isTradePause(Integer commoId) {
        try {
            int value = getParamValue(RiskNID.OPEN, commoId, Integer.class);
            if (value == 0) {
                return true;
            }
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BussinessException("系统繁忙，请稍后再试");
        }
    }

    @Override
    public String getContractNo(Integer commoId) {
        // 下期主力合约开始生效时间
        try {
            String nextDateStr = getParamValue(RiskNID.NEXT_CONTRACT_TIME, commoId);
            Date nextDate = new SimpleDateFormat("yyyy-MM-dd").parse(nextDateStr);
            if (new Date().after(nextDate)) {
                return getParamValue(RiskNID.NEXT_CONTRACT, commoId);
            } else {
                return getParamValue(RiskNID.CONTRACT, commoId);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public BigDecimal getFeeByAgent(Integer commoId, Integer agentId) {
        String nid = redisService.get(CacheID.COMMO_ID_PREFIX + commoId, Commo.class).getCode().toLowerCase() + "_fee";
        AgentConfig ac = agentConfigMapper.selectOne(new AgentConfig(t -> {
            t.setAgentId(agentId);
            t.setNid(nid);
            t.setDelFlag(GenericPo.DELFLAG.NORMAL.code);
        }));
        if (ac != null && StrUtil.isNotBlank(ac.getValue())) {
            return new BigDecimal(ac.getValue()).setScale(2, BigDecimal.ROUND_HALF_UP);
        } else {
            return getParamValue(RiskNID.FEE, commoId, BigDecimal.class).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
    }


    @Override
    public boolean isAutoCoverTime(Integer commoId) {
        try {
            SimpleDateFormat f1 = new SimpleDateFormat("yyyy-MM-dd");
            SimpleDateFormat f2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date now = new Date();

            String value = getParamValue(RiskNID.TRADE_TIME, commoId);

            String[] args = value.split(";");
            if (args.length == 1) {
                String[] times = args[0].split(",");
                Date autoCoverStart = f2.parse(f1.format(now) + " " + times[times.length - 1] + ":00");
                Date autoCoverEnd = DateUtil.offsetMinute(autoCoverStart, 5);
                if (autoCoverStart.compareTo(now) <= 0 && autoCoverEnd.compareTo(now) >= 0) {
                    return true;
                }
            } else if (args.length == 2) {
                String[] times1 = args[0].split(",");
                Date autoCoverStart1 = f2.parse(f1.format(now) + " " + times1[times1.length - 1] + ":00");
                Date autoCoverEnd1 = DateUtil.offsetMinute(autoCoverStart1, 5);
                if (autoCoverStart1.compareTo(now) <= 0 && autoCoverEnd1.compareTo(now) >= 0) {
                    return true;
                }

                String[] times2 = args[1].split(",");
                Date autoCoverStart2 = f2.parse(f1.format(now) + " " + times2[times2.length - 1] + ":00");
                Date autoCoverEnd2 = DateUtil.offsetMinute(autoCoverStart2, 5);
                if (autoCoverStart2.compareTo(now) <= 0 && autoCoverEnd2.compareTo(now) >= 0) {
                    return true;
                }
            }
            return false;
        } catch (ParseException e) {
            e.printStackTrace();
            throw new BussinessException("系统繁忙，请稍后再试");
        }
    }

}
